#include <string>
#include <unistd.h>
#include <cstdlib>
#include <vector>
#include <sys/types.h>
#include <functional>
#include <sys/wait.h>
#include "Channel.hpp"
#include "Task.hpp"

// typedef function<void()> work_t;
using work_t = function<void()>;

enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError,
};

class ProcessPool
{
public:
    ProcessPool(int n,work_t w):num(n),work(w)
    {}
    ~ProcessPool(){}
    // work_t work:回调
    int InitProcesspool()
    {
        for (int i = 0; i < num; i++)
        {
            // 1. 创建管道
            // 管道初始化成0
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return PipeError; // 管道创建失败
            // 2. 创建进程
            pid_t id = fork();
            if (id < 0)
                return ForkError; // 子进程创建失败

            // 创建通信信道
            if (id == 0)
            {
                close(pipefd[1]); // 关闭子进程的写窗口
                // 子进程

                // 原本读的是pipefd0的内容，现在重定向到标准输入，现在读端读取的就是标准输入
                dup2(pipefd[0], 0);
                work();  // 子进程需要做的工作
                exit(0); // 子进程干完工作直接结束
            }
            // 因为上面子进程执行完任务会直接退出，所以下面的代码只能是父进程执行
            close(pipefd[0]); // 关闭父进程的读窗口
            channels.emplace_back(pipefd[1], id);
        }
        return OK;
    }

    void DisPatchTasks()
    {
        int who = 0;
        // 派发任务
        int num = 20;
        while (num--)
        {
            // a.选择一个任务，整数
            int task = tmp.SelectTask();
            // b.选择一个子进程channel
            Channel &curr = channels[who];
            who++;
            who %= channels.size(); // 防止数组越界

            cout << "########################" << endl;
            cout << "send" << task << "to" << curr.Name() << ",任务还剩" << num << "个" << endl;
            cout << "########################" << endl;

            // c.派发任务
            curr.Send(task);

            sleep(1);
        }
    }

    void CleanProcessPool()
    {
        // for (auto &c : channels)
        // {
        //     // 调用关闭函数
        //     c.Close();
        // }
        // for (auto &e : channels)
        // {
        //     // 0:阻塞式等待
        //     pid_t rid = waitpid(e.Id(), nullptr, 0);
        //     if (rid > 0)
        //     {
        //         cout << "child " << rid << " wait...sucess" << endl;
        //     }
        // }
        for(int i = channels.size()-1;i >= 0;i--)
        {
            channels[i].Close();
            pid_t rid = waitpid(channels[i].Id(), nullptr, 0);
            if (rid > 0)
            {
                cout << "child " << rid << " wait...sucess" << endl;
            }
        }
    }

    void DebugPrint()
    {
        for (auto e : channels)
        {
            cout << e.Name() << endl;
        }
    }
private:
    vector<Channel> channels;
    int num;
    work_t work;
};